/**
 * layout - jQuery xui
 *
 * Licensed under the GPL:
 *   http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2013 xjb [ beymy.en@gmail.com ]
 *
 * 依赖
 *	panel
 */
(function($) {
    //设置layout大小位置
    function setSize(container) {
        var opts = $.data(container, 'layout').options;
        var panels = $.data(container, 'layout').panels;

        var cc = $(container);

        if (cc[0].tagName == 'BODY' || opts.fit == true) {
            var p = cc.parent();
            $(p).addClass('panel-noscroll');
            if (cc[0].tagName == 'BODY') {
                $('html').addClass('panel-fit');
            }
            cc.width(p.width()).height(p.height());
        } else {
            $(p).removeClass('panel-noscroll');
        }

        var cpos = {
            top: 0,
            left: 0,
            width: cc.width(),
            height: cc.height()
        };

        // 设置北面板大小位置
        function setNorthSize(pp) {
            if (pp.length == 0)
                return;
            pp.panel('resize', {
                width: cc.width(),
                height: pp.panel('options').height,
                left: 0,
                top: 0
            });
            cpos.top += pp.panel('options').height;
            cpos.height -= pp.panel('options').height;
        }

        // 设置南面板大小位置
        function setSouthSize(pp) {
            if (pp.length == 0)
                return;
            pp.panel('resize', {
                width: cc.width(),
                height: pp.panel('options').height,
                left: 0,
                top: cc.height() - pp.panel('options').height
            });
            cpos.height -= pp.panel('options').height;
        }

        // 设置东面板大小位置
        function setEastSize(pp) {
            if (pp.length == 0)
                return;
            pp.panel('resize', {
                width: pp.panel('options').width,
                height: cpos.height,
                left: cc.width() - pp.panel('options').width,
                top: cpos.top
            });
            cpos.width -= pp.panel('options').width;
        }

        // 设置西面板大小位置
        function setWestSize(pp) {
            if (pp.length == 0)
                return;
            pp.panel('resize', {
                width: pp.panel('options').width,
                height: cpos.height,
                left: 0,
                top: cpos.top
            });
            cpos.left += pp.panel('options').width;
            cpos.width -= pp.panel('options').width;
        }

        if (isVisible(panels.expandNorth)) {
            setNorthSize(panels.expandNorth);
        } else {
            setNorthSize(panels.north);
        }

        if (isVisible(panels.expandSouth)) {
            setSouthSize(panels.expandSouth);
        } else {
            setSouthSize(panels.south);
        }

        if (isVisible(panels.expandEast)) {
            setEastSize(panels.expandEast);
        } else {
            setEastSize(panels.east);
        }

        if (isVisible(panels.expandWest)) {
            setWestSize(panels.expandWest);
        } else {
            setWestSize(panels.west);
        }

        panels.center.panel('resize', cpos);
    }

    /**
     * 构建layout
     */
    function buildLayout(container) {
        var cc = $(container);

        cc.addClass('layout');

        function parseBuildPanels(cc) {
            cc.children("div").each(function() {
                var panelOpts = $.fn.layout.parsePanelOptions(this);
                if ($.inArray(panelOpts.region, ['north', 'south', 'east', 'west', 'center']) >= 0) {
                    buildPanel(container, panelOpts, this);
                }
            });
        };

        parseBuildPanels(cc);
        
        cc.append('<div class="layout-split-proxy-h"></div><div class="layout-split-proxy-v"></div>');

        bindEvents(container);
    }

    function bindEvents(container) {
        var cc = $(container);
        cc.unbind('.layout').bind('_resize.layout', function() {
            var opts = $.data(this, 'layout').options;
            if (this.tagName == 'BODY' || opts.fit == true) {
                setSize(this);
            }
            return false;
        });
    }

    /**
     * 构建layout panel
     */
    function buildPanel(container, panelOpts, el) {
        panelOpts.region = panelOpts.region || 'center';
        var panels = $.data(container, 'layout').panels;
        var cc = $(container);
        var dir = panelOpts.region;

        var pp = $(el);
        if (!pp.length) {
            pp = $('<div></div>').appendTo(cc);
        }

        var ppOpts = $.extend({}, $.fn.layout.panelDefaults, $.fn.layout.parsePanelOptions(pp[0]), {
            cls: ('layout-panel layout-panel-' + dir),
            onOpen: function() {
                var tools = $(this).panel('header').children('div.panel-tool');
                tools.children('a.panel-tool-collapse').hide();
                var arrow = {
                    north: 'up',
                    south: 'down',
                    east: 'right',
                    west: 'left'
                };
                if (!arrow[dir]) {
                    return;
                }
                var icon = 'layout-button-' + arrow[dir];
                var t = tools.children('a.' + icon);
                if (!t.length) {
                    t = $('<a href="javascript:void(0)"></a>').addClass(icon).appendTo(tools);
                    t.bind('click', {
                        dir: dir
                    }, function(e) {
                        collapsePanel(container, e.data.dir);
                        return false;
                    });
                }
            }
        }, panelOpts);
        pp.panel(ppOpts);
        panels[dir] = pp;

        //调整大小
        if (pp.panel('options').split) {
            var panel = pp.panel('panel');
            panel.addClass('layout-split-' + dir);

            var handles = [];
            if (dir == 'north') {
                handles.push('s');
            }
            if (dir == 'south') {
                handles.push('n');
            }
            if (dir == 'east') {
                handles.push('w');
            }
            if (dir == 'west') {
                handles.push('e');
            }

            panel.resizable({
                handles: handles,
                onStartResize: function(e) {
                    if (dir == 'north' || dir == 'south') {
                        var proxy = $('>div.layout-split-proxy-v', container);
                    } else {
                        var proxy = $('>div.layout-split-proxy-h', container);
                    }
                    var top = 0,
                        left = 0,
                        width = 0,
                        height = 0;
                    var pos = {
                        display: 'block'
                    };
                    if (dir == 'north') {
                        pos.top = (parseInt(panel.css('top')) || 0) + panel.outerHeight() - proxy.height();
                        pos.left = parseInt(panel.css('left')) || 0;
                        pos.width = panel.outerWidth();
                        pos.height = proxy.height();
                    } else if (dir == 'south') {
                        pos.top = parseInt(panel.css('top')) || 0;
                        pos.left = parseInt(panel.css('left')) || 0;
                        pos.width = panel.outerWidth();
                        pos.height = proxy.height();
                    } else if (dir == 'east') {
                        pos.top = parseInt(panel.css('top')) || 0;
                        pos.left = parseInt(panel.css('left')) || 0;
                        pos.width = proxy.width();
                        pos.height = panel.outerHeight();
                    } else if (dir == 'west') {
                        pos.top = parseInt(panel.css('top')) || 0;
                        pos.left = (parseInt(panel.css('left')) || 0) + panel.outerWidth() - proxy.width();
                        pos.width = proxy.width();
                        pos.height = panel.outerHeight();
                    }
                    proxy.css(pos);
                    $('<div class="layout-mask"></div>').css({
                        left: 0,
                        top: 0,
                        width: cc.width(),
                        height: cc.height()
                    }).appendTo(cc);
                },
                onResize: function(e) {
                    if (dir == 'north' || dir == 'south') {
                        var proxy = $('>div.layout-split-proxy-v', container);
                        proxy.css('top', e.pageY - $(container).offset().top - proxy.height() / 2);
                    } else {
                        var proxy = $('>div.layout-split-proxy-h', container);
                        proxy.css('left', e.pageX - $(container).offset().left - proxy.width() / 2);
                    }
                    return false;
                },
                onStopResize: function() {
                    $('>div.layout-split-proxy-v', container).css('display', 'none');
                    $('>div.layout-split-proxy-h', container).css('display', 'none');
                    var opts = pp.panel('options');
                    opts.width = panel.outerWidth();
                    opts.height = panel.outerHeight();
                    opts.left = panel.css('left');
                    opts.top = panel.css('top');
                    pp.panel('resize');
                    setSize(container);
                    cc.children('div.layout-mask').remove();
                }
            });
        }
        return pp;
    }

    /**
     * 收缩layout panel
     */
    function collapsePanel(container, region) {
        var panels = $.data(container, 'layout').panels;
        var cc = $(container);

        function createExpandPanel(dir) {
            var icon;
            if (dir == 'east')
                icon = 'layout-button-left'
            else if (dir == 'west')
                icon = 'layout-button-right'
            else if (dir == 'north')
                icon = 'layout-button-down'
            else if (dir == 'south')
                icon = 'layout-button-up';

            var p = $('<div></div>').appendTo(cc).panel({
                cls: 'layout-expand',
                title: '&nbsp;',
                closed: true,
                doSize: false,
                tools: [{
                    iconCls: icon,
                    handler: function() {
                        expandPanel(container, region);
                    }
                }]
            });
            p.panel('panel').hover(
                function() {
                    $(this).addClass('layout-expand-over');
                },
                function() {
                    $(this).removeClass('layout-expand-over');
                }
            );
            return p;
        }

        if (region == 'east') {
            panels.center.panel('resize', {
                width: panels.center.panel('options').width + panels.east.panel('options').width - 28
            });
            panels.east.panel('panel').animate({
                left: cc.width()
            }, function() {
                panels.east.panel('close');
                panels.expandEast.panel('open').panel('resize', {
                    top: panels.east.panel('options').top,
                    left: cc.width() - 28,
                    width: 28,
                    height: panels.east.panel('options').height
                });
            });
            if (!panels.expandEast) {
                panels.expandEast = createExpandPanel('east');
            }
        } else if (region == 'west') {
            panels.center.panel('resize', {
                width: panels.center.panel('options').width + panels.west.panel('options').width - 28,
                left: 28
            });
            panels.west.panel('panel').animate({
                left: -panels.west.panel('options').width
            }, function() {
                panels.west.panel('close');
                panels.expandWest.panel('open').panel('resize', {
                    top: panels.west.panel('options').top,
                    left: 0,
                    width: 28,
                    height: panels.west.panel('options').height
                });
            });
            if (!panels.expandWest) {
                panels.expandWest = createExpandPanel('west');
            }
        } else if (region == 'north') {
            var hh = cc.height() - 28;
            if (isVisible(panels.expandSouth)) {
                hh -= panels.expandSouth.panel('options').height;
            } else if (isVisible(panels.south)) {
                hh -= panels.south.panel('options').height;
            }
            panels.center.panel('resize', {
                top: 28,
                height: hh
            });
            panels.east.panel('resize', {
                top: 28,
                height: hh
            });
            panels.west.panel('resize', {
                top: 28,
                height: hh
            });
            if (isVisible(panels.expandEast)) {
                panels.expandEast.panel('resize', {
                    top: 28,
                    height: hh
                });
            }
            if (isVisible(panels.expandWest)) {
                panels.expandWest.panel('resize', {
                    top: 28,
                    height: hh
                });
            }

            panels.north.panel('panel').animate({
                top: -panels.north.panel('options').height
            }, function() {
                panels.north.panel('close');
                panels.expandNorth.panel('open').panel('resize', {
                    top: 0,
                    left: 0,
                    width: cc.width(),
                    height: 28
                });
            });
            if (!panels.expandNorth) {
                panels.expandNorth = createExpandPanel('north');
            }
        } else if (region == 'south') {
            var hh = cc.height() - 28;
            if (isVisible(panels.expandNorth)) {
                hh -= panels.expandNorth.panel('options').height;
            } else if (isVisible(panels.north)) {
                hh -= panels.north.panel('options').height;
            }
            panels.center.panel('resize', {
                height: hh
            });
            panels.east.panel('resize', {
                height: hh
            });
            panels.west.panel('resize', {
                height: hh
            });
            if (isVisible(panels.expandEast)) {
                panels.expandEast.panel('resize', {
                    height: hh
                });
            }
            if (isVisible(panels.expandWest)) {
                panels.expandWest.panel('resize', {
                    height: hh
                });
            }

            panels.south.panel('panel').animate({
                top: cc.height()
            }, function() {
                panels.south.panel('close');
                panels.expandSouth.panel('open').panel('resize', {
                    top: cc.height() - 28,
                    left: 0,
                    width: cc.width(),
                    height: 28
                });
            });
            if (!panels.expandSouth) {
                panels.expandSouth = createExpandPanel('south');
            }
        }
    }

    /**
     * 展开layout panel
     */
    function expandPanel(container, region) {
        var panels = $.data(container, 'layout').panels;
        var cc = $(container);
        if (region == 'east' && panels.expandEast) {
            panels.expandEast.panel('close');
            panels.east.panel('panel').stop(true, true);
            panels.east.panel('open').panel('resize', {
                left: cc.width()
            });
            panels.east.panel('panel').animate({
                left: cc.width() - panels.east.panel('options').width
            }, function() {
                setSize(container);
            });
        } else if (region == 'west' && panels.expandWest) {
            panels.expandWest.panel('close');
            panels.west.panel('panel').stop(true, true);
            panels.west.panel('open').panel('resize', {
                left: -panels.west.panel('options').width
            });
            panels.west.panel('panel').animate({
                left: 0
            }, function() {
                setSize(container);
            });
        } else if (region == 'north' && panels.expandNorth) {
            panels.expandNorth.panel('close');
            panels.north.panel('panel').stop(true, true);
            panels.north.panel('open').panel('resize', {
                top: -panels.north.panel('options').height
            });
            panels.north.panel('panel').animate({
                top: 0
            }, function() {
                setSize(container);
            });
        } else if (region == 'south' && panels.expandSouth) {
            panels.expandSouth.panel('close');
            panels.south.panel('panel').stop(true, true);
            panels.south.panel('open').panel('resize', {
                top: cc.height()
            });
            panels.south.panel('panel').animate({
                top: cc.height() - panels.south.panel('options').height
            }, function() {
                setSize(container);
            });
        }
    }

    function isVisible(pp) {
        if (!pp) return false;
        if (pp.length) {
            return pp.panel('panel').is(':visible');
        } else {
            return false;
        }
    }

    $.fn.layout = function(options, param) {
        if (typeof options == 'string') {
            return $.fn.layout.methods[options](this, param);
        }
        options = options || {};
        return this.each(function() {
            var state = $.data(this, 'layout');
            if (state) {
                $.extend(state.options, options);
            } else {
                var opts = $.extend({}, $.fn.layout.defaults, $.fn.layout.parseOptions(this), options);
                $.data(this, 'layout', {
                    options: opts,
                    panels: {
                        center: $(),
                        north: $(),
                        south: $(),
                        east: $(),
                        west: $()
                    }
                });
                buildLayout(this);
            }
            setSize(this);
        });
    };

    $.fn.layout.methods = {
        panel: function(jq, param) {
            return $.data(jq[0], 'layout').panels[param];
        },
        collapse: function(jq, param) {
            return jq.each(function() {
                collapsePanel(this, param);
            });
        },
        expand: function(jq, param) {
            return jq.each(function() {
                expandPanel(this, param);
            });
        }
    };

    $.fn.layout.parseOptions = function(target) {
        return $.extend({}, $.parser.parseOptions(target, [{
            fit: 'boolean'
        }]));
    };

    $.fn.layout.parsePanelOptions = function(target) {
        return $.extend({}, $.fn.panel.parseOptions(target), $.parser.parseOptions(target, ['region', {
            split: 'boolean'
        }]));
    };

    $.fn.layout.panelDefaults = $.extend({}, $.fn.panel.defaults, {
        region: null,
        split: false,
        collapsible: true,
        bodyCls: 'layout-body'
    });

    $.fn.layout.defaults = {
        fit: false
    };
})(jQuery);
